package com.alex.statistics.method.explorationAnalysis;


import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class VariableRelationAnalyzer {

    /**
     * 计算协方差
     *
     * @param xData 第一个变量数据
     * @param yData 第二个变量数据
     * @return 协方差值
     */
    public double calculateCovariance(List<Double> xData, List<Double> yData) {
        if (xData.size() != yData.size()) {
            throw new IllegalArgumentException("两个变量的数据长度必须相同");
        }

        int n = xData.size();
        if (n == 0) {
            return 0;
        }

        double xMean = calculateMean(xData);
        double yMean = calculateMean(yData);

        double sum = 0;
        for (int i = 0; i < n; i++) {
            sum += (xData.get(i) - xMean) * (yData.get(i) - yMean);
        }

        return sum / n;
    }

    /**
     * 计算皮尔逊相关系数
     *
     * @param xData 第一个变量数据
     * @param yData 第二个变量数据
     * @return 相关系数值 [-1, 1]
     */
    public double calculateCorrelation(List<Double> xData, List<Double> yData) {
        if (xData.size() != yData.size()) {
            throw new IllegalArgumentException("两个变量的数据长度必须相同");
        }

        int n = xData.size();
        if (n == 0) {
            return 0;
        }

        double covariance = calculateCovariance(xData, yData);
        double xStdDev = calculateStandardDeviation(xData);
        double yStdDev = calculateStandardDeviation(yData);

        if (xStdDev == 0 || yStdDev == 0) {
            return 0;
        }

        return covariance / (xStdDev * yStdDev);
    }

    private double calculateMean(List<Double> data) {
        return data.stream()
                .mapToDouble(Double::doubleValue)
                .average()
                .orElse(0);
    }

    private double calculateVariance(List<Double> data) {
        double mean = calculateMean(data);
        return data.stream()
                .mapToDouble(x -> Math.pow(x - mean, 2))
                .average()
                .orElse(0);
    }

    private double calculateStandardDeviation(List<Double> data) {
        return Math.sqrt(calculateVariance(data));
    }
}